using System;
using System.Drawing;
using System.Globalization;
using System.Runtime.InteropServices;
using PickGold.Charting;

namespace PickGold.Charting.ChartTypes
{
	internal class PointAndFigureChart : RangeColumnChart
	{
		private static bool _customizeSubscribed;

		protected override void DrawColumn2D(ChartGraphics graph, Axis vAxis, RectangleF rectSize, DataPoint point, Series ser)
		{
			double num = double.Parse(ser["CurrentBoxSize"], CultureInfo.InvariantCulture);
			double logValue = vAxis.GetLogValue(vAxis.ViewMinimum);
			logValue = Math.Abs((double)(vAxis.GetLinearPosition(logValue) - vAxis.GetLinearPosition(vAxis.GetLogValue(vAxis.ViewMinimum + num))));
			for (float i = rectSize.Y; i < (rectSize.Bottom - ((float)(logValue - (logValue / 4.0)))); i += (float)logValue)
			{
				RectangleF empty = RectangleF.Empty;
				empty.X = rectSize.X;
				empty.Y = i;
				empty.Width = rectSize.Width;
				empty.Height = (float)logValue;
				empty = graph.GetAbsoluteRectangle(empty);
				int num4 = 1 + (point.BorderWidth / 2);
				empty.Y += num4;
				empty.Height -= 2 * num4;
				RectangleF position = new RectangleF(empty.Location, empty.Size);
				position.Offset((float)ser.ShadowOffset, (float)ser.ShadowOffset);
				if (point.IsCustomPropertySet("PriceUpPoint"))
				{
					if (ser.ShadowOffset != 0)
					{
						graph.DrawLineAbs(ser.ShadowColor, point.BorderWidth, ChartDashStyle.Solid, new PointF(position.Left, position.Top), new PointF(position.Right, position.Bottom));
						graph.DrawLineAbs(ser.ShadowColor, point.BorderWidth, ChartDashStyle.Solid, new PointF(position.Left, position.Bottom), new PointF(position.Right, position.Top));
					}
					graph.DrawLineAbs(point.Color, point.BorderWidth, ChartDashStyle.Solid, new PointF(empty.Left, empty.Top), new PointF(empty.Right, empty.Bottom));
					graph.DrawLineAbs(point.Color, point.BorderWidth, ChartDashStyle.Solid, new PointF(empty.Left, empty.Bottom), new PointF(empty.Right, empty.Top));
				}
				else
				{
					if (ser.ShadowOffset != 0)
					{
						graph.DrawCircleAbs(new Pen(ser.ShadowColor, (float)point.BorderWidth), null, position, 1, false);
					}
					graph.DrawCircleAbs(new Pen(point.Color, (float)point.BorderWidth), null, empty, 1, false);
				}
			}
		}

		private static void FillPointAndFigureData(Series series, Series originalData)
		{
			double num3;
			double num4;
			int yValueHighIndex = 0;
			if (series.IsCustomPropertySet("UsedYValueHigh"))
			{
				try
				{
					yValueHighIndex = int.Parse(series["UsedYValueHigh"], CultureInfo.InvariantCulture);
				}
				catch
				{
					throw new InvalidOperationException(SR.ExceptionPointAndFigureUsedYValueHighInvalidFormat);
				}
				if (yValueHighIndex >= series.YValuesPerPoint)
				{
					throw new InvalidOperationException(SR.ExceptionPointAndFigureUsedYValueHighOutOfRange);
				}
			}
			int yValueLowIndex = 1;
			if (series.IsCustomPropertySet("UsedYValueLow"))
			{
				try
				{
					yValueLowIndex = int.Parse(series["UsedYValueLow"], CultureInfo.InvariantCulture);
				}
				catch
				{
					throw new InvalidOperationException(SR.ExceptionPointAndFigureUsedYValueLowInvalidFormat);
				}
				if (yValueLowIndex >= series.YValuesPerPoint)
				{
					throw new InvalidOperationException(SR.ExceptionPointAndFigureUsedYValueLowOutOfrange);
				}
			}
			Color color = ChartGraphics.GetGradientColor(series.Color, Color.Black, 0.5);
			string text = series["PriceUpColor"];
			if (text != null)
			{
				try
				{
					ColorConverter converter = new ColorConverter();
					color = (Color)converter.ConvertFromString(null, CultureInfo.InvariantCulture, text);
				}
				catch
				{
					throw new InvalidOperationException(SR.ExceptionPointAndFigureUpBrickColorInvalidFormat);
				}
			}
			GetPriceRange(originalData, yValueHighIndex, yValueLowIndex, out num3, out num4);
			double num5 = GetBoxSize(series, num3, num4);
			double reversalAmount = GetReversalAmount(series);
			double naN = double.NaN;
			double num8 = double.NaN;
			int num9 = 0;
			int num10 = 0;
			foreach (DataPoint point in originalData.Points)
			{
				if (!point.IsEmpty)
				{
					bool flag = false;
					int num11 = 0;
					if (double.IsNaN(naN))
					{
						naN = point.YValues[yValueHighIndex];
						num8 = point.YValues[yValueLowIndex];
						num10++;
						continue;
					}
					int num12 = 0;
					switch (num9)
					{
						case 1:
						case 0:
							if (point.YValues[yValueHighIndex] >= (naN + num5))
							{
								num12 = 1;
								num11 = (int)Math.Floor((double)((point.YValues[yValueHighIndex] - naN) / num5));
							}
							else if (point.YValues[yValueLowIndex] <= (naN - (num5 * reversalAmount)))
							{
								num12 = -1;
								num11 = (int)Math.Floor((double)((naN - point.YValues[yValueLowIndex]) / num5));
							}
							else if (point.YValues[yValueHighIndex] <= (num8 - num5))
							{
								flag = true;
								num11 = (int)Math.Floor((double)((num8 - point.YValues[yValueHighIndex]) / num5));
								if (series.Points.Count > 0)
								{
									series.Points[series.Points.Count - 1].YValues[0] -= num11 * num5;
								}
								num8 -= num11 * num5;
							}
							break;
					}
					if ((num12 == 0) && ((num9 == -1) || (num9 == 0)))
					{
						if (point.YValues[yValueLowIndex] <= (num8 - num5))
						{
							num12 = -1;
							num11 = (int)Math.Floor((double)((num8 - point.YValues[yValueLowIndex]) / num5));
						}
						else if (point.YValues[yValueHighIndex] >= (num8 + (num5 * reversalAmount)))
						{
							num12 = 1;
							num11 = (int)Math.Floor((double)((point.YValues[yValueHighIndex] - num8) / num5));
						}
						else if (point.YValues[yValueLowIndex] >= (naN + num5))
						{
							flag = true;
							num11 = (int)Math.Floor((double)((naN - point.YValues[yValueLowIndex]) / num5));
							if (series.Points.Count > 0)
							{
								series.Points[series.Points.Count - 1].YValues[1] += num11 * num5;
							}
							naN += num11 * num5;
						}
					}
					if ((num12 != 0) && !flag)
					{
						if (num12 == num9)
						{
							if (num12 == 1)
							{
								series.Points[series.Points.Count - 1].YValues[1] += num11 * num5;
								naN += num11 * num5;
								series.Points[series.Points.Count - 1]["OriginalPointIndex"] = num10.ToString(CultureInfo.InvariantCulture);
							}
							else
							{
								series.Points[series.Points.Count - 1].YValues[0] -= num11 * num5;
								num8 -= num11 * num5;
								series.Points[series.Points.Count - 1]["OriginalPointIndex"] = num10.ToString(CultureInfo.InvariantCulture);
							}
						}
						else
						{
							DataPoint item = point.Clone();
							item["OriginalPointIndex"] = num10.ToString(CultureInfo.InvariantCulture);
							item.series = series;
							item.XValue = point.XValue;
							if (num12 == 1)
							{
								item.Color = color;
								item["PriceUpPoint"] = "true";
								item.YValues[0] = num8 + ((num9 != 0) ? num5 : 0.0);
								item.YValues[1] = (item.YValues[0] + (num11 * num5)) - ((num9 != 0) ? num5 : 0.0);
							}
							else
							{
								item.YValues[1] = naN - ((num9 != 0) ? num5 : 0.0);
								item.YValues[0] = item.YValues[1] - (num11 * num5);
							}
							naN = item.YValues[1];
							num8 = item.YValues[0];
							series.Points.Add(item);
						}
						num9 = num12;
					}
				}
				num10++;
			}
		}

		private static double GetBoxSize(Series series, double minPrice, double maxPrice)
		{
			double num = 1.0;
			double num2 = 4.0;
			bool flag = true;
			if (series.IsCustomPropertySet("BoxSize"))
			{
				string s = series["BoxSize"].Trim();
				bool flag2 = s.EndsWith("%", StringComparison.Ordinal);
				if (flag2)
				{
					s = s.Substring(0, s.Length - 1);
				}
				bool flag3 = false;
				if (flag2)
				{
					double num3;
					flag3 = double.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out num3);
					if (flag3)
					{
						num2 = num3;
						flag = false;
					}
				}
				else
				{
					double result = 0.0;
					flag3 = double.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out result);
					if (flag3)
					{
						num = result;
						num2 = 0.0;
					}
				}
				if (!flag3)
				{
					throw new InvalidOperationException(SR.ExceptionRenkoBoxSizeFormatInvalid);
				}
			}
			if (num2 > 0.0)
			{
				num = 1.0;
				if (minPrice == maxPrice)
				{
					num = 1.0;
				}
				else if ((maxPrice - minPrice) < 1E-06)
				{
					num = 1E-06;
				}
				else
				{
					num = (maxPrice - minPrice) * (num2 / 100.0);
				}
				if (flag)
				{
					double[] numArray = new double[] { 
                        1E-06, 1E-05, 0.0001, 0.001, 0.01, 0.1, 0.25, 0.5, 1.0, 2.0, 2.5, 3.0, 4.0, 5.0, 7.5, 10.0, 
                        15.0, 20.0, 25.0, 50.0, 100.0, 200.0, 500.0, 1000.0, 5000.0, 10000.0, 50000.0, 100000.0, 1000000.0, 1000000.0
                     };
					for (int i = 1; i < numArray.Length; i++)
					{
						if ((num > numArray[i - 1]) && (num < numArray[i]))
						{
							num = numArray[i];
						}
					}
				}
			}
			series["CurrentBoxSize"] = num.ToString(CultureInfo.InvariantCulture);
			return num;
		}

		public override Image GetImage(ChartTypeRegistry registry)
		{
			return (Image)registry.ResourceManager.GetObject(this.Name + "ChartType");
		}

		private static void GetPriceRange(Series originalData, int yValueHighIndex, int yValueLowIndex, out double minPrice, out double maxPrice)
		{
			maxPrice = double.MinValue;
			minPrice = double.MaxValue;
			foreach (DataPoint point in originalData.Points)
			{
				if (point.IsEmpty)
				{
					continue;
				}
				if (point.YValues.Length < 2)
				{
					int num = 2;
					throw new InvalidOperationException(SR.ExceptionChartTypeRequiresYValues("PointAndFigure", num.ToString(CultureInfo.CurrentCulture)));
				}
				if (point.YValues[yValueHighIndex] > maxPrice)
				{
					maxPrice = point.YValues[yValueHighIndex];
				}
				else if (point.YValues[yValueLowIndex] > maxPrice)
				{
					maxPrice = point.YValues[yValueLowIndex];
				}
				if (point.YValues[yValueHighIndex] < minPrice)
				{
					minPrice = point.YValues[yValueHighIndex];
				}
				else if (point.YValues[yValueLowIndex] < minPrice)
				{
					minPrice = point.YValues[yValueLowIndex];
				}
			}
		}

		private static double GetReversalAmount(Series series)
		{
			double num2;
			double num = 3.0;
			if (!series.IsCustomPropertySet("ReversalAmount"))
			{
				return num;
			}
			if (!double.TryParse(series["ReversalAmount"].Trim(), NumberStyles.Any, CultureInfo.InvariantCulture, out num2))
			{
				throw new InvalidOperationException(SR.ExceptionPointAndFigureReversalAmountInvalidFormat);
			}
			return num2;
		}

		private static void OnCustomize(object sender, EventArgs e)
		{
			bool flag = false;
			Chart chart = (Chart)sender;
			foreach (Series series in chart.Series)
			{
				if (series.Name.StartsWith("POINTANDFIGURE_ORIGINAL_DATA_", StringComparison.Ordinal))
				{
					Series series2 = chart.Series[series.Name.Substring(0x1d)];
					bool flag2 = true;
					string strA = series2["ProportionalSymbols"];
					if ((strA != null) && (string.Compare(strA, "True", StringComparison.OrdinalIgnoreCase) != 0))
					{
						flag2 = false;
					}
					if ((flag2 && series2.Enabled) && (series2.ChartArea.Length > 0))
					{
						if (!flag)
						{
							flag = true;
							chart.ChartPicture.Resize(chart.ChartPicture.ChartGraph, false);
						}
						ChartArea area = chart.ChartAreas[series2.ChartArea];
						Axis axis = area.GetAxis(AxisName.X, series2.XAxisType, series2.XSubAxisName);
						Axis axis2 = area.GetAxis(AxisName.Y, series2.YAxisType, series2.YSubAxisName);
						if (!area.Area3DStyle.Enable3D)
						{
							double num = double.Parse(series2["CurrentBoxSize"], CultureInfo.InvariantCulture);
							double num2 = Math.Abs((double)(axis2.GetPosition(axis2.Minimum) - axis2.GetPosition(axis2.Minimum + num)));
							double num3 = Math.Abs((double)(axis.GetPosition(1.0) - axis.GetPosition(0.0))) * 0.8;
							SizeF absoluteSize = chart.ChartPicture.ChartGraph.GetAbsoluteSize(new SizeF((float)num3, (float)num2));
							int num4 = 0;
							if (absoluteSize.Width > absoluteSize.Height)
							{
								num4 = (int)(series2.Points.Count * (absoluteSize.Width / absoluteSize.Height));
							}
							DataPoint item = new DataPoint(series2);
							item.IsEmpty = true;
							item.AxisLabel = " ";
							while (series2.Points.Count < num4)
							{
								series2.Points.Add(item);
							}
							series2["EmptyPointValue"] = "Zero";
							area.ReCalcInternal();
						}
					}
				}
			}
		}

		internal static void PrepareData(Series series)
		{
			if ((string.Compare(series.ChartTypeName, "PointAndFigure", StringComparison.OrdinalIgnoreCase) == 0) && series.IsVisible())
			{
				Chart chart = series.Chart;
				if (chart == null)
				{
					throw new InvalidOperationException(SR.ExceptionPointAndFigureNullReference);
				}
				ChartArea area = chart.ChartAreas[series.ChartArea];
				foreach (Series series2 in chart.Series)
				{
					if ((series2.IsVisible() && (series2 != series)) && (area == chart.ChartAreas[series2.ChartArea]))
					{
						throw new InvalidOperationException(SR.ExceptionPointAndFigureCanNotCombine);
					}
				}
				if (!_customizeSubscribed)
				{
					_customizeSubscribed = true;
					chart.Customize += new EventHandler(PointAndFigureChart.OnCustomize);
				}
				string name = "POINTANDFIGURE_ORIGINAL_DATA_" + series.Name;
				if (chart.Series.IndexOf(name) == -1)
				{
					Series item = new Series(name, series.YValuesPerPoint);
					item.Enabled = false;
					item.IsVisibleInLegend = false;
					item.YValuesPerPoint = series.YValuesPerPoint;
					chart.Series.Add(item);
					foreach (DataPoint point in series.Points)
					{
						item.Points.Add(point);
					}
					series.Points.Clear();
					if (series.IsCustomPropertySet("TempDesignData"))
					{
						item["TempDesignData"] = "true";
					}
					series["OldXValueIndexed"] = series.IsXValueIndexed.ToString(CultureInfo.InvariantCulture);
					series["OldYValuesPerPoint"] = series.YValuesPerPoint.ToString(CultureInfo.InvariantCulture);
					series.IsXValueIndexed = true;
					if ((series.ChartArea.Length > 0) && series.IsXValueDateTime())
					{
						Axis axis = area.GetAxis(AxisName.X, series.XAxisType, series.XSubAxisName);
						if ((axis.Interval == 0.0) && (axis.IntervalType == DateTimeIntervalType.Auto))
						{
							bool flag = false;
							double maxValue = double.MaxValue;
							double minValue = double.MinValue;
							foreach (DataPoint point2 in item.Points)
							{
								if (!point2.IsEmpty)
								{
									if (point2.XValue != 0.0)
									{
										flag = true;
									}
									if (point2.XValue > minValue)
									{
										minValue = point2.XValue;
									}
									if (point2.XValue < maxValue)
									{
										maxValue = point2.XValue;
									}
								}
							}
							if (flag)
							{
								series["OldAutomaticXAxisInterval"] = "true";
								DateTimeIntervalType auto = DateTimeIntervalType.Auto;
								axis.interval = axis.CalcInterval(maxValue, minValue, true, out auto, series.XValueType);
								axis.intervalType = auto;
							}
						}
					}
					FillPointAndFigureData(series, item);
				}
			}
		}

		internal static bool UnPrepareData(Series series)
		{
			bool flag;
			int num;
			if (!series.Name.StartsWith("POINTANDFIGURE_ORIGINAL_DATA_", StringComparison.Ordinal))
			{
				return false;
			}
			Chart chart = series.Chart;
			if (chart == null)
			{
				throw new InvalidOperationException(SR.ExceptionPointAndFigureNullReference);
			}
			if (_customizeSubscribed)
			{
				_customizeSubscribed = false;
				chart.Customize -= new EventHandler(PointAndFigureChart.OnCustomize);
			}
			Series fromSeries = chart.Series[series.Name.Substring(0x1d)];
			Series.MovePositionMarkers(fromSeries, series);
			fromSeries.Points.Clear();
			if (!series.IsCustomPropertySet("TempDesignData"))
			{
				foreach (DataPoint point in series.Points)
				{
					fromSeries.Points.Add(point);
				}
			}
			bool flag2 = bool.TryParse(fromSeries["OldXValueIndexed"], out flag);
			fromSeries.IsXValueIndexed = flag2 && flag;
			if (int.TryParse(fromSeries["OldYValuesPerPoint"], NumberStyles.Any, CultureInfo.InvariantCulture, out num))
			{
				fromSeries.YValuesPerPoint = num;
			}
			fromSeries.DeleteCustomProperty("OldXValueIndexed");
			fromSeries.DeleteCustomProperty("OldYValuesPerPoint");
			fromSeries.DeleteCustomProperty("EmptyPointValue");
			series["OldAutomaticXAxisInterval"] = "true";
			if (fromSeries.IsCustomPropertySet("OldAutomaticXAxisInterval"))
			{
				fromSeries.DeleteCustomProperty("OldAutomaticXAxisInterval");
				if (fromSeries.ChartArea.Length > 0)
				{
					Axis axis = chart.ChartAreas[fromSeries.ChartArea].GetAxis(AxisName.X, fromSeries.XAxisType, fromSeries.XSubAxisName);
					axis.interval = 0.0;
					axis.intervalType = DateTimeIntervalType.Auto;
				}
			}
			chart.Series.Remove(series);
			return true;
		}

		public override string Name
		{
			get
			{
				return "PointAndFigure";
			}
		}
	}
}

